【作ってみた】オンライン会議中にON AIRライトを点ける
CX事業本部チームIoTの熊膳です。
リモートワークでのオンライン会議、家族に気を使われることってありませんか?例えば、音を立てないようにとか、カメラに映り込まないようにとか。うちはあります。 でも、私、一日中ヘッドホンしているので、家族からするといつオンライン会議しているのか、すごくわかりにくいです。
というわけで、GWの企画として「オンライン会議中にON AIRライトを点ける」仕組みを作ってみました。
オンライン会議 ON AIRライトシステム
最初に動いている動画を紹介します。
ちょっとだけタイムラグがありますが、会議が始まるとON AIRが点灯し、終了すると消えています。
作ってみた
「オンライン会議中」をどう判断するか?という部分をどうしようかと悩んだのですが、結論としてはWebカメラがONになっている時としました。オンライン会議=カメラONではないのですが、やりたいことはカメラがONになってることを伝えたいということなので問題ないです。
作戦はこうです。
- 何らかの仕組みでカメラの状態を検知する。
- カメラの状態がOFFからONになったらON AIRライトをつける。ONからOFFなら消す。
ON AIRライトのON/OFFは、スマートプラグを使いました。
参考までに、今回使った機材は以下です。
- Webカメラ
- スマートプラグ
- ON AIRライト
カメラの状態の検知
まずはカメラの状態をどうやって取得するかです。
私の使用しているWebカメラは「ロジクールStreamCam」で、MacとはUSB-Cケーブルで接続しています。最初はUSBハブ経由で電気的な違いを取得するとか、カメラONのライトをコンピュータビジョンを用いて検出するとか、出来もしないことを考えていたのですが、カメラ起動中は何かのプロセスが動いているはずとの妄想を元に、アクティビティモニタを「cam」で検索したところ、LogiFacecamServiceというプロセスを見つけました。
カメラをON/OFFしたところ、CPUの値が変化していることを発見。これ使えそうです。
以下のコマンドで、CPUの値を取得できました。
ps -o %cpu -o comm -ax|grep LogiFacecam 14.7 /Library/Application Support/LogiFacecam.bundle/Contents/MacOS/LogiFacecamService
上記の14.7というのがCPUの値です。CPUの値が、0.0より大きい場合をカメラONと判断することにします。
【追記】 実際に何日か運用してみると、カメラONの場合でもタイミングによっては0.0になる場合があるようです。OFFになったと判断する場合は、0.0が2,3回続くという条件にしたほうが良さそうです。
ON AIRライトの点灯
ON AIRライトの点灯、消灯は、スマートプラグを使用します。今回使ったHS105は、tplink-smarthome-apiを用いることで、Macから制御できますのでこれを使います。
セットアップの仕方や、ライブラリの使い方は、山本さんやMiyajimaさんのブログを参考にしました。
ロジックは以下としました。
- 前回のカメラの状態をファイルから読み込む
- プロセスを取得し前回のカメラの状態から変更があったら
- スマートプラグで電源のON/OFFを行う
- カメラの状態をファイルに書き込む
コード
私、エンジニアじゃないのでコードとしては微妙かもしれないですが、一応動いているコードはこちらになります。
const fs = require('fs'); const childProcess = require('child_process'); const client = new (require('tplink-smarthome-api').Client)(); const CMD ='ps -o %cpu -o comm -ax|grep LogiFacecam'; const FILE = '/<ステータスファイルのパス>/state'; const PLUGIP = '192.168.x.x'; // HS105のIPアドレス tplink-smarthome-api searchで事前に調べておく const lastStatus = fs.readFileSync(FILE, 'utf-8'); const cmd = childProcess.spawn(CMD, [], {shell: true}); cmd.stdout.on('data', (data) => { console.log(data.toString()); // 1番目の数値をCPU値として取り出す const cpu = data.toString().trim().split(' ')[0]; // cpuが0より大きい場合は、カメラが起動中と判断する const cameraStatus = (Number(cpu) > 0 ? 'ON' : 'OFF'); console.log(cameraStatus); // カメラの起動状態が変更したらファイルを更新しONAIR状態を更新する if (lastStatus !== cameraStatus) { // ファイルを更新 fs.writeFile(FILE, cameraStatus, (err) => { if (err) throw err; }); // ON AIR ライトの変更 client.getDevice({ host: PLUGIP }).then((device) => { if (device.deviceType === 'plug') { device.setPowerState(cameraStatus === 'ON' ? true : false); } }); } });
スクリプト起動
Macを使っているので上記のスクリプトをlaunchdで定期起動することにします。
以下のplistファイルを~/Library/LaunchAgents/xxx.plist
として配置します。ファイル名はjp.classmethod.seisho.kumazen.onair.plist
としました。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>jp.classmethod.seisho.kumazen.onair</string> <key>ProgramArguments</key> <array> <string>/usr/local/bin/node</string> <string>/<スクリプトのパス>/onair.js</string> </array> <key>StartInterval</key> <integer>5</integer> <key>StandardOutPath</key> <string>/<スクリプトのパス>/log.out</string> <key>StandardErrorPath</key> <string>/<スクリプトのパス>/log.err</string> </dict> </plist>
起動間隔は、撮影の都合上5秒にしてますが、そこまでリアルタイムじゃなくていいと考え60秒でもいいかなと思ってます。StartInterval
の値で変更可能です。
ファイルを配置したら、以下のコマンドを実行して完了です。
launchctl load ~/Library/LaunchAgents/jp.classmethod.seisho.kumazen.onair.plist
ちなみに停止は、上記のload
をunload
に変更して実行です。
まとめ
GWの自由研究として、「オンライン会議中にON AIRライトを点ける」をやってみました。 この「オンライン会議中に」というイベントをトリガーに何かを行うというのは、色々応用できそうですね。例えば「LEDライトを点灯する」というのは、すぐに出来そうです。
以上、どなたかの参考になれば幸いです。